"""
统一工具模块 - 整合所有辅助功能
"""

import time
import hashlib
import hmac
import base64
import json
import asyncio
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional, Union, Callable
from decimal import Decimal, ROUND_HALF_UP
import pandas as pd
import numpy as np


class TimeUtils:
    """时间工具类"""
    
    @staticmethod
    def now() -> datetime:
        """获取当前时间"""
        return datetime.now(timezone.utc)
    
    @staticmethod
    def timestamp() -> int:
        """获取当前时间戳（毫秒）"""
        return int(time.time() * 1000)
    
    @staticmethod
    def from_timestamp(timestamp: Union[int, float]) -> datetime:
        """从时间戳转换为datetime"""
        if timestamp > 1e10:  # 毫秒时间戳
            timestamp = timestamp / 1000
        return datetime.fromtimestamp(timestamp, timezone.utc)
    
    @staticmethod
    def to_timestamp(dt: datetime) -> int:
        """datetime转换为时间戳（毫秒）"""
        return int(dt.timestamp() * 1000)
    
    @staticmethod
    def format_time(dt: datetime, fmt: str = "%Y-%m-%d %H:%M:%S") -> str:
        """格式化时间为统一格式 yyyy-MM-dd HH:mm:ss"""
        return dt.strftime(fmt)
    
    @staticmethod
    def parse_time(time_str: str, fmt: str = "%Y-%m-%d %H:%M:%S") -> datetime:
        """解析时间字符串"""
        return datetime.strptime(time_str, fmt).replace(tzinfo=timezone.utc)
    
    @staticmethod
    def parse_datetime(time_str: str, fmt: str = "%Y-%m-%d %H:%M:%S") -> datetime:
        """解析时间字符串（别名方法）"""
        return TimeUtils.parse_time(time_str, fmt)
    
    @staticmethod
    def add_time(dt: datetime, **kwargs) -> datetime:
        """时间加法"""
        return dt + timedelta(**kwargs)
    
    @staticmethod
    def time_diff(dt1: datetime, dt2: datetime) -> timedelta:
        """计算时间差"""
        return dt1 - dt2
    
    @staticmethod
    def is_trading_time(dt: datetime = None) -> bool:
        """判断是否为交易时间（简化版）"""
        if dt is None:
            dt = TimeUtils.now()
        
        # 简单判断：周一到周五
        return dt.weekday() < 5
    
    @staticmethod
    def get_interval_timedelta(interval: str) -> timedelta:
        """
        获取时间间隔的timedelta对象
        
        Args:
            interval: 时间间隔字符串 (1m, 5m, 30m, 1h, 2h, 1d, 1w等)
            
        Returns:
            timedelta对象
        """
        interval_map = {
            # 分钟级别
            '1m': timedelta(minutes=1),
            '3m': timedelta(minutes=3),
            '5m': timedelta(minutes=5),
            '15m': timedelta(minutes=15),
            '30m': timedelta(minutes=30),
            
            # 小时级别
            '1h': timedelta(hours=1),
            '2h': timedelta(hours=2),
            '4h': timedelta(hours=4),
            '6h': timedelta(hours=6),
            '8h': timedelta(hours=8),
            '12h': timedelta(hours=12),
            
            # 天级别
            '1d': timedelta(days=1),
            '3d': timedelta(days=3),
            
            # 周级别
            '1w': timedelta(weeks=1),
            
            # 月级别（近似）
            '1M': timedelta(days=30),
        }
        
        if interval not in interval_map:
            raise ValueError(f"不支持的时间间隔: {interval}")
        
        return interval_map[interval]
    
    @staticmethod
    def standardize_timestamp(timestamp: Any, unit: str = 'ms') -> datetime:
        """
        标准化时间戳
        
        Args:
            timestamp: 时间戳
            unit: 单位 ('ms', 's', 'ns')
            
        Returns:
            标准化的datetime对象
        """
        if isinstance(timestamp, datetime):
            return timestamp.replace(tzinfo=timezone.utc) if timestamp.tzinfo is None else timestamp
        
        if isinstance(timestamp, str):
            # 尝试解析ISO格式
            try:
                dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
                return dt.replace(tzinfo=timezone.utc) if dt.tzinfo is None else dt
            except ValueError:
                # 尝试解析为数字时间戳
                timestamp = float(timestamp)
        
        # 转换数字时间戳
        if unit == 'ms':
            timestamp = timestamp / 1000
        elif unit == 'ns':
            timestamp = timestamp / 1000000000
        
        return datetime.fromtimestamp(timestamp, timezone.utc)
    
    @staticmethod
    def to_standard_format(timestamp: Any, unit: str = 'ms') -> str:
        """
        将时间戳转换为标准格式字符串 yyyy-MM-dd HH:mm:ss
        
        Args:
            timestamp: 时间戳（可以是datetime、int、float、str）
            unit: 时间戳单位 ('ms', 's', 'ns')
            
        Returns:
            格式化的时间字符串 yyyy-MM-dd HH:mm:ss
        """
        dt = TimeUtils.standardize_timestamp(timestamp, unit)
        return dt.strftime('%Y-%m-%d %H:%M:%S')
    
    @staticmethod
    def now_standard() -> str:
        """
        获取当前时间的标准格式字符串 yyyy-MM-dd HH:mm:ss
        
        Returns:
            当前时间的格式化字符串
        """
        return datetime.now().strftime('%Y-%m-%d %H:%M:%S')


class MathUtils:
    """数学工具类"""
    
    @staticmethod
    def round_decimal(value: Union[float, Decimal], precision: int = 8) -> Decimal:
        """精确小数舍入"""
        if isinstance(value, float):
            value = Decimal(str(value))
        elif not isinstance(value, Decimal):
            value = Decimal(str(value))
        
        return value.quantize(Decimal('0.' + '0' * precision), rounding=ROUND_HALF_UP)
    
    @staticmethod
    def calculate_percentage(value: float, total: float) -> float:
        """计算百分比"""
        if total == 0:
            return 0.0
        return (value / total) * 100
    
    @staticmethod
    def calculate_change_rate(old_value: float, new_value: float) -> float:
        """计算变化率"""
        if old_value == 0:
            return 0.0
        return ((new_value - old_value) / old_value) * 100
    
    @staticmethod
    def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float:
        """安全除法"""
        if denominator == 0:
            return default
        return numerator / denominator
    
    @staticmethod
    def clamp(value: float, min_val: float, max_val: float) -> float:
        """限制数值范围"""
        return max(min_val, min(value, max_val))


class DataUtils:
    """数据工具类"""
    
    @staticmethod
    def safe_get(data: Dict[str, Any], key: str, default: Any = None) -> Any:
        """安全获取字典值"""
        return data.get(key, default)
    
    @staticmethod
    def deep_get(data: Dict[str, Any], keys: str, default: Any = None) -> Any:
        """深度获取嵌套字典值，支持点号分隔"""
        try:
            for key in keys.split('.'):
                data = data[key]
            return data
        except (KeyError, TypeError):
            return default
    
    @staticmethod
    def merge_dicts(*dicts: Dict[str, Any]) -> Dict[str, Any]:
        """合并多个字典"""
        result = {}
        for d in dicts:
            result.update(d)
        return result
    
    @staticmethod
    def filter_dict(data: Dict[str, Any], keys: List[str]) -> Dict[str, Any]:
        """过滤字典，只保留指定键"""
        return {k: v for k, v in data.items() if k in keys}
    
    @staticmethod
    def flatten_dict(data: Dict[str, Any], separator: str = '.') -> Dict[str, Any]:
        """扁平化嵌套字典"""
        def _flatten(obj, parent_key=''):
            items = []
            if isinstance(obj, dict):
                for k, v in obj.items():
                    new_key = f"{parent_key}{separator}{k}" if parent_key else k
                    items.extend(_flatten(v, new_key).items())
            else:
                return {parent_key: obj}
            return dict(items)
        
        return _flatten(data)
    
    @staticmethod
    def to_dataframe(data: List[Dict[str, Any]]) -> pd.DataFrame:
        """转换为DataFrame"""
        return pd.DataFrame(data)
    
    @staticmethod
    def from_dataframe(df: pd.DataFrame) -> List[Dict[str, Any]]:
        """从DataFrame转换"""
        return df.to_dict('records')


class CryptoUtils:
    """加密工具类"""
    
    @staticmethod
    def generate_signature(secret: str, message: str, algorithm: str = 'sha256') -> str:
        """生成HMAC签名"""
        return hmac.new(
            secret.encode('utf-8'),
            message.encode('utf-8'),
            getattr(hashlib, algorithm)
        ).hexdigest()
    
    @staticmethod
    def generate_signature_base64(secret: str, message: str, algorithm: str = 'sha256') -> str:
        """生成Base64编码的HMAC签名"""
        signature = hmac.new(
            secret.encode('utf-8'),
            message.encode('utf-8'),
            getattr(hashlib, algorithm)
        ).digest()
        return base64.b64encode(signature).decode('utf-8')
    
    @staticmethod
    def md5_hash(text: str) -> str:
        """MD5哈希"""
        return hashlib.md5(text.encode('utf-8')).hexdigest()
    
    @staticmethod
    def sha256_hash(text: str) -> str:
        """SHA256哈希"""
        return hashlib.sha256(text.encode('utf-8')).hexdigest()


class ValidationUtils:
    """验证工具类"""
    
    @staticmethod
    def is_valid_symbol(symbol: str) -> bool:
        """验证交易对格式"""
        if not symbol or not isinstance(symbol, str):
            return False
        
        # 简单验证：包含-或/分隔符
        return '-' in symbol or '/' in symbol or symbol.isupper()
    
    @staticmethod
    def is_positive_number(value: Any) -> bool:
        """验证是否为正数"""
        try:
            return float(value) > 0
        except (ValueError, TypeError):
            return False
    
    @staticmethod
    def is_valid_price(price: Any) -> bool:
        """验证价格有效性"""
        return ValidationUtils.is_positive_number(price)
    
    @staticmethod
    def is_valid_quantity(quantity: Any) -> bool:
        """验证数量有效性"""
        return ValidationUtils.is_positive_number(quantity)
    
    @staticmethod
    def validate_required_fields(data: Dict[str, Any], required_fields: List[str]) -> List[str]:
        """验证必需字段"""
        missing_fields = []
        for field in required_fields:
            if field not in data or data[field] is None:
                missing_fields.append(field)
        return missing_fields


class AsyncUtils:
    """异步工具类"""
    
    @staticmethod
    async def run_with_timeout(coro, timeout: float):
        """带超时的异步执行"""
        return await asyncio.wait_for(coro, timeout=timeout)
    
    @staticmethod
    async def gather_with_limit(tasks: List, limit: int = 10):
        """限制并发数的gather"""
        semaphore = asyncio.Semaphore(limit)
        
        async def limited_task(task):
            async with semaphore:
                return await task
        
        return await asyncio.gather(*[limited_task(task) for task in tasks])
    
    @staticmethod
    def run_in_executor(func: Callable, *args, executor=None):
        """在执行器中运行同步函数"""
        loop = asyncio.get_event_loop()
        return loop.run_in_executor(executor, func, *args)


class FormatUtils:
    """格式化工具类"""
    
    @staticmethod
    def format_number(value: float, precision: int = 2) -> str:
        """格式化数字"""
        return f"{value:.{precision}f}"
    
    @staticmethod
    def format_percentage(value: float, precision: int = 2) -> str:
        """格式化百分比"""
        return f"{value:.{precision}f}%"
    
    @staticmethod
    def format_currency(value: float, currency: str = "USD", precision: int = 2) -> str:
        """格式化货币"""
        return f"{value:.{precision}f} {currency}"
    
    @staticmethod
    def format_size(bytes_size: int) -> str:
        """格式化文件大小"""
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if bytes_size < 1024.0:
                return f"{bytes_size:.1f} {unit}"
            bytes_size /= 1024.0
        return f"{bytes_size:.1f} PB"
    
    @staticmethod
    def truncate_string(text: str, max_length: int, suffix: str = "...") -> str:
        """截断字符串"""
        if len(text) <= max_length:
            return text
        return text[:max_length - len(suffix)] + suffix


class RetryUtils:
    """重试工具类"""
    
    @staticmethod
    async def async_retry(func: Callable, max_attempts: int = 3, delay: float = 1.0, 
                         backoff: float = 2.0, exceptions: tuple = (Exception,)):
        """异步重试装饰器"""
        for attempt in range(max_attempts):
            try:
                return await func()
            except exceptions as e:
                if attempt == max_attempts - 1:
                    raise e
                await asyncio.sleep(delay * (backoff ** attempt))
    
    @staticmethod
    def sync_retry(func: Callable, max_attempts: int = 3, delay: float = 1.0,
                  backoff: float = 2.0, exceptions: tuple = (Exception,)):
        """同步重试装饰器"""
        for attempt in range(max_attempts):
            try:
                return func()
            except exceptions as e:
                if attempt == max_attempts - 1:
                    raise e
                time.sleep(delay * (backoff ** attempt))


# 便捷访问实例
time_utils = TimeUtils()
math_utils = MathUtils()
data_utils = DataUtils()
crypto_utils = CryptoUtils()
validation_utils = ValidationUtils()
async_utils = AsyncUtils()
format_utils = FormatUtils()
retry_utils = RetryUtils()